package me.sealer.ssm.utils;

import com.alibaba.druid.util.HttpClientUtils;
import me.sealer.ssm.exception.SsmException;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author sealer
 * @date 2017/06/17
 */
public class UrlUtil {
    public static final int BASE62_SIZE = 62;
    /**
     * 用于62进制中的各个数值, 真正使用之前， 可以做一次shuffle(千万不要将shuffle用在程序运行时， 很耗费时间， 而且也不应该每一次重新运行时都shuffle， 否则会出现重复的短地址)
     */
    private static final String[] BASE62 = {"z", "8", "Z", "5", "A", "4", "I", "W", "F", "C", "r", "k", "a", "f", "G", "v", "o", "l", "B", "j", "L", "Q", "1", "Y", "K", "h", "9", "D", "2", "J", "e", "6", "O", "7", "u", "3", "m", "t", "q", "i", "x", "M", "s", "w", "U", "y", "0", "V", "N", "b", "T", "g", "P", "R", "d", "c", "X", "p", "H", "n", "E", "S"};
    private static final String[] BASE62_1 = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
    private static final String[] BASE62_2 = {"t", "f", "2", "1", "g", "L", "y", "q", "i", "Y", "Q", "K", "a", "l", "V", "3", "4", "r", "5", "z", "c", "k", "D", "7", "n", "C", "A", "R", "T", "S", "B", "G", "s", "x", "e", "u", "E", "v", "w", "8", "b", "o", "6", "P", "N", "M", "F", "O", "U", "h", "I", "d", "j", "0", "J", "H", "Z", "m", "X", "9", "W", "p"};
    private static final String[] BASE62_3 = {"3", "h", "o", "q", "g", "H", "Q", "J", "Y", "r", "t", "O", "i", "d", "U", "I", "0", "Z", "T", "e", "N", "W", "c", "L", "X", "f", "y", "M", "F", "P", "V", "4", "S", "x", "C", "G", "s", "K", "5", "b", "2", "z", "p", "A", "l", "7", "R", "v", "k", "n", "a", "E", "6", "m", "1", "9", "j", "D", "8", "u", "B", "w"};
    private static final String[] BASE62_4 = {"0", "4", "3", "n", "z", "V", "e", "X", "R", "9", "m", "l", "c", "I", "K", "Z", "S", "v", "P", "q", "5", "Y", "O", "G", "6", "b", "f", "C", "x", "k", "w", "a", "1", "H", "o", "h", "E", "M", "N", "s", "g", "L", "t", "i", "A", "y", "D", "d", "7", "r", "T", "u", "B", "Q", "W", "F", "8", "2", "p", "J", "U", "j"};

    /**
     * 把10进制数字转换为62进制每一位的下标数组
     * 62进制数字存放在一个Integer泛型的List中
     *
     * @param from 待转换的10进制数字
     * @return
     */
    private static List<Integer> base10ToBase62Indices(long from) {
        List<Integer> value = new ArrayList<>();
        //62进制的个位
        long remain = from % BASE62_SIZE;
        value.add((int) remain);
        //62进制数右移一位
        from /= BASE62_SIZE;
        while (from >= BASE62_SIZE) {
            //62进制的个位
            remain = from % BASE62_SIZE;
            value.add((int) remain);
            //62进制数右移一位
            from /= BASE62_SIZE;
        }
        value.add((int) from);
        return value;
    }


    /**
     * shuffle函数， 用来打乱62进制中的每位的表示字母
     * 仅在程序运行前用来确定62个数字字母的顺序， 顺序一旦确定， 不可更改。
     *
     * @param args 待shuffle的字符串数组
     */
    private static void shuffle(String[] args) {
        int length = args.length;
        for (int i = 0; i < length; i++) {
            int random = new Random(System.currentTimeMillis()).nextInt(BASE62_SIZE);
            try {
                Thread.sleep(new Random().nextInt(111));
            } catch (InterruptedException e) {
                throw new SsmException(e);
            }
            String s = args[i];
            args[i] = args[random];
            args[random] = s;
        }
    }


    /**
     * 这个算法的NB之处在于：
     * 当短地址下标list的长度小于6时， 前边会自动补充
     * 当短地址下标list的长度大于6时， 地址长度会自动扩充
     * 即短地址几乎用不完， 最多long型数据最大值 个短地址
     *
     * @param list 这里代表的是62进制的下标数组
     * @param bits 短地址的位数
     * @return 返回值即为短地址
     */
    private static String indexList2String(List<Integer> list, int bits) {
        String s = "";
        int length = list.size();
        for (int i = 0; i < bits - length; i++) {
            s += index2String(0);
        }

        //这里注意顺序， i从length-1倒着开始的
        for (int i = length - 1; i >= 0; i--) {
            s += index2String(list.get(i));
        }

        return s;
    }

    /**
     * 根据下标拿到BASE62中对应位置的字母或数字
     *
     * @param index
     * @return
     */
    private static String index2String(int index) {
        return BASE62[index];
    }

    /**
     * 获取短地址的方法, 也是该方法唯一对外开放的静态方法
     *
     * @param from 10进制数字，用来转为62进制数
     * @param bits 短地址的位数
     * @return 短地址
     */
    public static String genShortUrl(long from, int bits) {
        List<Integer> list = base10ToBase62Indices(from);
        return indexList2String(list, bits);
    }

    /**
     * 组装url
     *
     * @param protocolDomain 协议+域名
     * @param resource       资源路径
     * @return url
     */
    public static String assembleUrl(String protocolDomain, String resource) {
        while (protocolDomain.endsWith("/")) {
            protocolDomain = protocolDomain.substring(0, protocolDomain.length() - 1);
        }

        while (resource.startsWith("/")) {
            resource = resource.substring(1);
        }

        return protocolDomain + "/" + resource;
    }

    /**
     * 用来打印BASE62数组用， 真正计算短地址不会用到
     *
     * @param list
     */
    private static void printList(String[] list) {
        System.out.print("{");
        for (int i = 0; i < list.length - 1; i++) {
            System.out.print("\"" + list[i] + "\", ");
        }
        System.out.println("\"" + list[list.length - 1] + "\"};");
    }

    public static void main(String[] args) {
//        shuffle(BASE62);
//        printList(BASE62);
//        String s = getShortUrl(1, 6);
//        System.out.println(s);
    }
}
